package icu.twtool.database.mapper

import com.aventrix.jnanoid.jnanoid.NanoIdUtils
import icu.twtool.database.DatabaseUtil
import icu.twtool.database.model.ExerciseMetaData
import icu.twtool.entity.BinaryEquationBase
import icu.twtool.generator.EquationGenerator
import icu.twtool.generator.ExerciseGenerator
import icu.twtool.util.PathUtil
import java.io.PrintStream
import kotlin.io.path.deleteIfExists
import kotlin.io.path.outputStream

/**
 * @author Wen
 * @since 2022-11-02
 */
object ExerciseMeteDataMapper {

    private const val ID = "ID"
    const val NAME = "NAME"
    const val COUNT = "COUNT"
    private const val TYPE = "TYPE"
    const val REALLY_NAME = "REALLY_NAME"

    private val equationBase = BinaryEquationBase(100)
    private val generator = ExerciseGenerator(equationGenerator = EquationGenerator(0..100))

    fun selectPage(offset: Int, size: Int): List<ExerciseMetaData> {
        return DatabaseUtil.connection {
            val result = mutableListOf<ExerciseMetaData>()
            val resultSet =
                prepareStatement("select ID, NAME, `TYPE`, COUNT, REALLY_NAME from TB_EXERCISE_METE_DATA limit ? offset ?")
                    .apply {
                        setInt(1, size)
                        setInt(2, offset)
                    }
                    .executeQuery()
            while (resultSet.next()) {
                result.add(
                    ExerciseMetaData(
                        resultSet.getInt(ID),
                        resultSet.getString(NAME),
                        resultSet.getString(TYPE),
                        resultSet.getInt(COUNT),
                        resultSet.getString(REALLY_NAME),
                    )
                )
            }
            result
        } ?: listOf()
    }

    fun deleteById(id: Int): Boolean {
        return DatabaseUtil.transactionConnection {
            val reallyName = prepareStatement("select REALLY_NAME from TB_EXERCISE_METE_DATA where ID = ?").run {
                setInt(1, id)
                val resultSet = executeQuery()
                if (resultSet.next()) {
                    resultSet.getString(1)
                } else null
            }
            reallyName?.let {
                return@let prepareStatement("delete from TB_EXERCISE_METE_DATA where ID = ?").run {
                    setInt(1, id)
                    execute()
                    val r = updateCount > 0
                    if (r) {
                        prepareStatement("select PRACTICE_FILE from TB_PRACTICE_RECORD where EXERCISE_ID = ?").run {
                            setInt(1, id)
                            val resultSet = executeQuery()
                            while (resultSet.next()) {
                                PathUtil.practice().resolve(resultSet.getString(1)).deleteIfExists()
                            }
                        }
                        prepareStatement("delete from TB_PRACTICE_RECORD where EXERCISE_ID = ?").run {
                            setInt(1, id)
                            execute()
                        }
                        val path = PathUtil.exercise().resolve(it)
                        println(path)
                        path.deleteIfExists()
                    }
                    r
                }
            }
        } ?: false
    }

    fun insert(name: String, type: String, equationCount: Int): Boolean {
        // 使用事务
        return DatabaseUtil.transactionConnection {
            val reallyName = NanoIdUtils.randomNanoId()
            prepareStatement("insert into TB_EXERCISE_METE_DATA(NAME, `TYPE`, COUNT, REALLY_NAME) values (?, ?, ?, ?)").apply {
                setString(1, name)
                setString(2, type)
                setInt(3, equationCount)
                setString(4, reallyName)
            }.run {
                execute()
                val result = updateCount > 0
                val stream = PrintStream(PathUtil.exercise().resolve(reallyName).outputStream())
                val generateMethod = when (type) {
                    "混合" -> generator::generateOfRandomByBase
                    "加法" -> generator::generateOfAdditionsByBase
                    else -> generator::generateOfSubtractionByBase
                }
                generateMethod(equationCount, equationBase).write(answer = false, out = stream)
                stream.close()
                result
            }
        } ?: false
    }

    fun count(): Int {
        return DatabaseUtil.connection {
            val resultSet = prepareCall("select count(ID) from TB_EXERCISE_METE_DATA").executeQuery()
            if (resultSet.next()) {
                resultSet.getInt(1)
            } else 0
        } ?: 0
    }
}